#include "Object.h"



Object::Object (UINT type, Player owner,
                Ptr< ObjectProperty > pObjProperty,
                Ptr< Terrain > pTerrian,
                float x, float y,
                int number, float forward)
                : _type (type), _owner (owner), _porperty (pObjProperty),
                _pTerrian (pTerrian),
                _numberLeft (number), _forwardAngle (forward)
{
  _centerPos = Position3f (x, y, _pTerrian->altitude (x, y));
  Position3f pos1 (x - 1.0, y - 1.0, _pTerrian->altitude (x - 1.0, y - 1.0));
  Position3f pos2 (x + 1.0, y - 1.0, _pTerrian->altitude (x + 1.0, y - 1.0));
  Position3f pos3 (x - 1.0, y + 1.0, _pTerrian->altitude (x - 1.0, y + 1.0));
  _3D_Vector v1 (pos1.data (), pos3.data ());
  _3D_Vector v2 (pos1.data (), pos2.data ());
  _rotation = v2.cross (v1);
  //_rotation = _pTerrian->normal (x, y);
  _targetPos = Position3f (-1, -1, -1);
  _fightTarget = NULL;
  _selected = true;
  _underAttack = false;
}



// ========================================================================
// Getter Functions
// ========================================================================

UINT Object::type_id () const
{
  return _type;
}


Player Object::owner () const
{
  return _owner;
}

const Position3f& Object::center () const
{
  return _centerPos;
}

const Rotation3f& Object::rotation () const
{
  return _rotation;
}


float Object::forward_angle () const
{
  return _forwardAngle;
}

const Position3f& Object::target_pos () const
{
  return _targetPos;
}

const Ptr< Object > Object::fight_target () const
{
  return _fightTarget;
}

int Object::number_left () const
{
  if ((float)(int)_numberLeft != _numberLeft)
    return (int) _numberLeft + 1;
  return _numberLeft;
}



bool Object::selected () const
{
  return _selected;
}

bool Object::under_attack () const
{
  return _underAttack;
}

bool Object::exist () const
{
  if (_numberLeft > 0) return true;
  return false;
}



const Ptr< ObjectProperty > Object::properties () const
{
  return _porperty;
}



// ========================================================================
// Control Functions
// ========================================================================


void Object::set_target (float x, float y)
{
  _fightTarget = NULL;
  _targetPos = Position3f (x, y, _pTerrian->altitude (x, y));
}

void Object::set_target (Object* target)
{
  _targetPos = Position3f (-1, -1, -1);
  _fightTarget = target;
}

void Object::select ()
{
  _selected = true;
}

void Object::deselect ()
{
  _selected = false;
}



// Return false if it has died and should be remove from the battle
bool Object::update ()
{

  if (!exist ()) return false;
  
  if (_fightTarget != NULL)
    _fight ();

  _move ();

  return true;

}


// ========================================================================
// Private Functions
// ========================================================================

void Object::_fight ()
{
	float a = _centerPos.distance (_fightTarget->_centerPos);
  if (a <= _porperty->basic_attack_range ())
  {
    _targetPos = Position3f (-1, -1, -1);
    _attack (_fightTarget);
  }
  else _trace_target ();
}

void Object::_attack (Ptr< Object > target)
{
  target->_underAttack = true;
  target->_be_attacked_by (this);
}

void Object::_be_attacked_by (Ptr< Object > enemy)
{
  if (_fightTarget == NULL)
    _fightTarget = enemy;
  _numberLeft -= 
    (float)((int) _numberLeft + 1) * 
    enemy->_porperty->basic_attack_power () *
    (1.0f - enemy->_porperty->basic_missing_chance ()) *
    (1.0f - _porperty->basic_avoiding_chance ()) - 
    (float)((int)_numberLeft + 1) * _porperty->basic_defence ();
}

void Object::_trace_target ()
{
  _targetPos = _fightTarget->_centerPos;
}

void Object::_move ()
{

  // Whether has reached the target
  if (_centerPos.distance (_targetPos) < _porperty->radius ())
    _targetPos = Position3f (-1, -1, -1);

  if (_targetPos[0] != -1)
  {

    // Calculate direction
    _3D_Vector centerToTarget = _targetPos - _centerPos;
    centerToTarget[2] = 0;
    centerToTarget.unitary ();
    centerToTarget *= _porperty->speed ();

    // Move
    _centerPos += centerToTarget;

    // Set proper z value
    _centerPos[2] = _pTerrian->altitude (_centerPos[0], _centerPos[1]);

    // Set rotation
    _rotation = _pTerrian->normal (_centerPos[0], _centerPos[1]);
  }

}


